import Cesium from '../Ces/Cesium'

const distances = [
  1, 2, 3, 5,
  10, 20, 30, 50,
  100, 200, 300, 500,
  1000, 2000, 3000, 5000,
  10000, 20000, 30000, 50000,
  100000, 200000, 300000, 500000,
  1000000, 2000000, 3000000, 5000000,
  10000000, 20000000, 30000000, 50000000,
]

const cartesian2Scratch1 = new Cesium.Cartesian2()
const cartesian3Scratch1 = new Cesium.Cartesian3()
const cartographicScratch1 = new Cesium.Cartographic()
const cartographicScratch2 = new Cesium.Cartographic()
const rayScratch1 = new Cesium.Ray()

class ScaleListener {
  _geodesic = new Cesium.EllipsoidGeodesic()
  lastFrameNumber = 0
  _currentScale = distances[distances.length - 1]
  _currentLod = distances.length - 1
  _scaleChangedEvent = new Cesium.Event()
  _removeEventSubscription
  lastCameraPosition
  onScale: any
  constructor() {
    this._removeEventSubscription = this._scaleChangedEvent.addEventListener(
      this._onScale,
      this,
    )
    this.lastCameraPosition = new Cesium.Cartesian3()
  }

  get currentScale() {
    return this._currentScale
  }
  get currentLod() {
    return this._currentLod
  }

  _onScale(sender, distance, pixelDistance) {
    if (Cesium.defined(this.onScale)) {
      this.onScale(sender, distance, pixelDistance)
    }
  }

  isDestroyed() {
    return false
  }

  destroy() {
    this._removeEventSubscription()
  }


  update(scene, _time) {
    const frameNumber = scene.frameState.frameNumber
    if (!scene.globe.show) return
    if (frameNumber - this.lastFrameNumber < 10) {
      return
    }
    this.lastFrameNumber = frameNumber

    const cameraPositions = scene.camera.position
    if (this.lastCameraPosition.equalsEpsilon(cameraPositions, Cesium.Math.EPSILON6)) {
      return
    }
    cameraPositions.clone(this.lastCameraPosition)

    const width = scene.canvas.clientWidth
    const height = scene.canvas.clientHeight

    const getPosition = (offsetX, result) => {
      cartesian2Scratch1.x = (width / 2 | 0) + offsetX
      cartesian2Scratch1.y = height - 1
      const ray = scene.camera.getPickRay(cartesian2Scratch1, rayScratch1)
      const cartesian3 = scene.globe.pick(ray, scene, cartesian3Scratch1)
      if (!cartesian3) return
      return scene.globe.ellipsoid.cartesianToCartographic(cartesian3, result)
    }

    const leftCartographic = getPosition(0, cartographicScratch1)
    if (!Cesium.defined(leftCartographic)) {
      this.lastCameraPosition.x = 0
      return
    }

    const rightCartographic = getPosition(1, cartographicScratch2)
    if (!Cesium.defined(rightCartographic)) {
      this.lastCameraPosition.x = 0
      return
    }

    this._geodesic.setEndPoints(leftCartographic, rightCartographic)
    const pixelDistance = this._geodesic.surfaceDistance
    const maxBarWidth = 100

    let distance

    let i = distances.length - 1
    for (; i >= 0; --i) {
      if (distances[i] / pixelDistance < maxBarWidth) {
        distance = distances[i]
        break
      }
    }
    if (Cesium.defined(distance)) {
      if (this._currentScale !== distance) {
        this._currentScale = distance
        this._currentLod = i
        this._scaleChangedEvent.raiseEvent(this, distance, pixelDistance, '')
      }
    }
  }
}

export default ScaleListener
